{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Widgets without writing widgets: interact"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The `interact` function (`ipywidgets.interact`) automatically creates user interface (UI) controls for exploring code and data interactively. It is the easiest way to get started using IPython's widgets."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "from ipywidgets import interact, interactive, fixed, interact_manual\n",
    "import ipywidgets as widgets"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Basic `interact`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "At the most basic level, `interact` autogenerates UI controls for function arguments, and then calls the function with those arguments when you manipulate the controls interactively. To use `interact`, you need to define a function that you want to explore. Here is a function that triples its argument, `x`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def f(x):\n",
    "    return 3 * x"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "When you pass this function as the first argument to `interact` along with an integer keyword argument (`x=10`), a slider is generated and bound to the function parameter."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "interact(f, x=10);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "When you move the slider, the function is called, and the return value is printed.\n",
    "\n",
    "If you pass `True` or `False`, `interact` will generate a checkbox:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "interact(f, x=True);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If you pass a string, `interact` will generate a `Text` field."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "interact(f, x='Hi there!');"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`interact` can also be used as a decorator. This allows you to define a function and interact with it in a single shot. As this example shows, `interact` also works with functions that have multiple arguments."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "@interact(x=True, y=1.0)\n",
    "def g(x, y):\n",
    "    return (x, y)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Fixing arguments using `fixed`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "There are times when you may want to explore a function using `interact`, but fix one or more of its arguments to specific values. This can be accomplished by wrapping values with the `fixed` function."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def h(p, q):\n",
    "    return (p, q)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "When we call `interact`, we pass `fixed(20)` for q to hold it fixed at a value of `20`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "interact(h, p=5, q=fixed(20));"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Notice that a slider is only produced for `p` as the value of `q` is fixed."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Widget abbreviations"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "When you pass an integer-valued keyword argument of `10` (`x=10`) to `interact`, it generates an integer-valued slider control with a range of `[-10,+3*10]`. In this case, `10` is an *abbreviation* for an actual slider widget:\n",
    "\n",
    "```python\n",
    "IntSlider(min=-10,max=30,step=1,value=10)\n",
    "```\n",
    "\n",
    "In fact, we can get the same result if we pass this `IntSlider` as the keyword argument for `x`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "interact(f, x=widgets.IntSlider(min=-10, max=30, step=1, value=10));"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This examples clarifies how `interact` proceses its keyword arguments:\n",
    "\n",
    "1. If the keyword argument is a `Widget` instance with a `value` attribute, that widget is used. Any widget with a `value` attribute can be used, even custom ones.\n",
    "2. Otherwise, the value is treated as a *widget abbreviation* that is converted to a widget before it is used.\n",
    "\n",
    "The following table gives an overview of different widget abbreviations:\n",
    "\n",
    "<table class=\"table table-condensed table-bordered\">\n",
    "  <tr><td><strong>Keyword argument</strong></td><td><strong>Widget</strong></td></tr>  \n",
    "  <tr><td>`True` or `False`</td><td>Checkbox</td></tr>  \n",
    "  <tr><td>`'Hi there'`</td><td>Text</td></tr>\n",
    "  <tr><td>`value` or `(min,max)` or `(min,max,step)` if integers are passed</td><td>IntSlider</td></tr>\n",
    "  <tr><td>`value` or `(min,max)` or `(min,max,step)` if floats are passed</td><td>FloatSlider</td></tr>\n",
    "  <tr><td>`['orange','apple']` or `[('one', 1), ('two', 2)]`</td><td>Dropdown</td></tr>\n",
    "</table>\n",
    "Note that a dropdown is used if a list or a list of tuples is given (signifying discrete choices), and a slider is used if a tuple is given (signifying a range)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You have seen how the checkbox and textarea widgets work above. Here, more details about the different abbreviations for sliders and dropdowns are given.\n",
    "\n",
    "If a 2-tuple of integers is passed `(min,max)`, an integer-valued slider is produced with those minimum and maximum values (inclusively). In this case, the default step size of `1` is used."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "interact(f, x=(0, 4));"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A `FloatSlider` is generated if any of the values are floating point. The step size can be changed by passing a third element in the tuple."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "interact(f, x=(0, 10, 0.01));"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "For both integer and float-valued sliders, you can pick the initial value of the widget by passing a default keyword argument to the underlying Python function. Here we set the initial value of a float slider to `5.5`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "@interact(x=(0.0, 20.0, 0.5))\n",
    "def h(x=5.5):\n",
    "    return x"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Dropdown menus are constructed by passing a list of strings. In this case, the strings are both used as the names in the dropdown menu UI and passed to the underlying Python function."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "interact(f, x=['apples','oranges']);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If you want a dropdown menu that passes non-string values to the Python function, you can pass a list of tuples of the form `('label', value)`. The first items are the names in the dropdown menu UI and the second items are values that are the arguments passed to the underlying Python function."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "interact(f, x=[('one', 10), ('two', 20)]);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## `interactive`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In addition to `interact`, IPython provides another function, `interactive`, that is useful when you want to reuse the widgets that are produced or access the data that is bound to the UI controls.\n",
    "\n",
    "Note that unlike `interact`, the return value of the function will not be displayed automatically, but you can display a value inside the function with `IPython.display.display`."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Here is a function that returns the sum of its two arguments and displays them."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "from IPython.display import display\n",
    "\n",
    "def f(a, b):\n",
    "    display(a + b)\n",
    "    return a+b"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Unlike `interact`, `interactive` returns a `Widget` instance rather than immediately displaying the widget."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "w = interactive(f, a=10, b=20)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The widget is an `interactive`, a subclass of `VBox`, which is a container for other widgets."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "type(w)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The children of the `interactive` are two integer-valued sliders and an output widget, produced by the widget abbreviations above."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "w.children"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To actually display the widgets, you can use IPython's `display` function."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "display(w)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "At this point, the UI controls work just like they would if `interact` had been used. You can manipulate them interactively and the function will be called. However, the widget instance returned by `interactive` also gives you access to the current keyword arguments and return value of the underlying Python function. \n",
    "\n",
    "Here are the current keyword arguments. If you rerun this cell after manipulating the sliders, the values will have changed."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "w.kwargs"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Here is the current return value of the function."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "w.result"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Basic interactive plot\n",
    "\n",
    "Though the examples so far in this notebook had very basic output, more interesting possibilities are straightforward. \n",
    "\n",
    "The function below plots a straight line whose slope and intercept are given by its arguments."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "%matplotlib inline\n",
    "import matplotlib.pyplot as plt\n",
    "import numpy as np\n",
    "\n",
    "def f(m, b):\n",
    "    plt.figure(2)\n",
    "    x = np.linspace(-10, 10, num=1000)\n",
    "    plt.plot(x, m * x + b)\n",
    "    plt.ylim(-5, 5)\n",
    "    plt.show()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The interactive below displays a line whose slope and intercept is set by the sliders. Note that if the variable containing the widget, `interactive_plot`, is the last thing in the cell it is displayed."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "interactive_plot = interactive(f, m=(-2.0, 2.0), b=(-3, 3, 0.5))\n",
    "interactive_plot"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Disabling continuous updates"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "When interacting with long running functions, or even with short functions whose results take some to display, realtime feedback is a burden instead of being helpful. You might have noticed the output of some of the widgets above \"flickering\" as you adjusted the controls. By default, `interact` and `interactive` call the function for every update of the widgets value. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "There are two ways to mitigate this.  You can either only execute on demand, or restrict execution to mouse release events."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### `interact_manual`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The `interact_manual` function provides a variant of interaction that allows you to restrict execution so it is only done on demand.  A button is added to the interact controls that allows you to trigger an execute event."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def slow_function(i):\n",
    "    \"\"\"\n",
    "    Sleep for 1 second then print the argument\n",
    "    \"\"\"\n",
    "    from time import sleep\n",
    "    print('Sleeping...')\n",
    "    sleep(1)\n",
    "    print(i)\n",
    "\n",
    "interact_manual(slow_function,i=widgets.FloatSlider(min=1e4, max=1e6, step=1e4));"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can do the same thing with `interactive` by using the a `dict` as the second argument, as shown below."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "foo = interactive(slow_function, {'manual': True}, i=widgets.FloatSlider(min=1e4, max=1e6, step=1e4))\n",
    "foo"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### `continuous_update`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If you are using slider widgets, you can set the `continuous_update` kwarg to `False`.  `continuous_update` is a keyword argument of slider widgets that restricts executions to mouse release events.\n",
    "\n",
    "In ipywidgets 7, the `Text` and `Textarea` controls also have a `continuous_update` argument.\n",
    "\n",
    "The first example below provides the `continuous_update` argument when the widget is created."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "interact(slow_function,i=widgets.FloatSlider(min=1e4, max=1e6, step=5e4, continuous_update=False));"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Exercise\n",
    "\n",
    "The interactive plot above lags quite a bit when you change the sliders. Recall that `interactive_plot` is a widget with three children: one for each slider and one for displaying output. Execute the cell below, then scroll back up to try the graph with sliders again.\n",
    "\n",
    "The cell below changes one of the sliders so that the graph only updates when the slider is released; if you use `interactive` you have access to all of the widget's properties and can change them later.\n",
    "\n",
    "If you have time, modify the cell below so that the other slider also behaves that way."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "interactive_plot.children[0].continuous_update = False\n",
    "# Add your code here"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "# For more information \n",
    "\n",
    "For more extended examples of `interact` and `interactive`, see [the example in the ipywidgets source repository](https://github.com/jupyter-widgets/ipywidgets/blob/master/docs/source/examples/Index.ipynb)."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "widgets-tutorial",
   "language": "python",
   "name": "widgets-tutorial"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
